/** \brief File defining a Life's game cell
 *
 * This file contains the declaration of the class implementing a cell of the
 * Game of Life.
 *
 * @file Cell.hpp
 * @author Johan "Solo" Luisier
 * @date 2013/03/21
 */
#ifndef CELL_HPP
#define CELL_HPP

#include <QtCore/QList>
#include <QtCore/QObject>

class RuleData;

/** @brief The Cell class implements a cell for the Game of Life.
 *
 * This class implements the logic of a cell for the Game of Life. It holds
 * pointers on its neighbours, lists of birth and survival conditions. A method
 * can compute the state of the cell for the next iteration depending on the
 * rules and the state of the neighbouring cells. The implementation does not
 * depend on the number of neighbours, meaning that it is independent from the
 * visualisation.
 *
 * @author Johan "Solo" Luisier
 * @date 2013/03/21
 *
 * @class Cell "Cell.hpp" "Core/Cell.hpp"
 */
class Cell : public QObject
{
    Q_OBJECT
public:

    /** @brief Enumeration for the different allowed states of a Cell instance.
     */
    enum Status
    {
        /** Unknown (i.e. not initialised) state, is also used for uncomputed @e
         * future state.
         */
        Unknown = -1,
        /** This state correspond to a dead Cell.
         */
        Dead = 0,
        /** This state correspond to a living Cell.
         */
        Alive = 1
    };

    /** @brief Default constructor.
     *
     * The constructor initialises the current state to Dead and the future
     * state to Unknown.
     *
     * @param[in] parent pointer on the QObject parent.
     */
    Cell( QObject* parent = 0 );
    /** @brief Destructor, virtual to ensure a proper destruction sequence.
     *
     * The destructor has nothing special to do.
     */
    ~Cell();
    /** @brief Getter for Neighbours.
     *
     * This method allows to access Neighbours.
     *
     * @return a const reference on Neighbours.
     */
    const QList< Cell* >& neighbours() const;
    /** @brief Method allowing to add a neighbour to the instance.
     *
     * This method allows to add a neighbour to the current instance. A
     * neighbourhood relationship is materialised by the instance holding a
     * pointer on its neighbour.
     *
     * If the new neighbour is already in the Neighbours container, it is not
     * added a second time.
     *
     * The method does nothing if the argument is a null pointer.
     *
     * @param[in] neighbour pointer on the new neighbouring instance.
     */
    void addNeighbour( Cell* neighbour );
    /** @brief method allowing to remove a neighbour from the instance.
     *
     * This method allows to remove a neighbour from the current instance.
     *
     * If the neighbour to remove is in the Neighbours container, it is
     * removed.
     *
     * @param[in] neighbour pointer on the neighbouring instance to remove.
     *
     * @retval true if the instance to remove was found and removed, @retval
     * false if it is not a neighbour of the current instance.
     */
    bool removeNeighbour( Cell* neighbour );
    /** @brief Method allowing to remove @e all the neighbours.
     *
     * This method allows to remove @e all the %neighbours of the current
     * instance, by clearing the Neighbours container.
     */
    void clearNeighbours();
    void setLifeRules(RuleData *ptr );
//    /* @brief Getter for the BirthConditions.
//     *
//     * This method allows to access BirthConditions.
//     *
//     * @return a const reference on BirthConditions.
//     */
//    const QList< quint8 >& birthConditions() const;
//    /* @brief Setter for BirthConditions.
//     *
//     * This method allows to modify BirthConditions.
//     *
//     * @param[in] conds new values for BirthConditions.
//     */
//    void setBirthConditions( const QList< quint8 >& conds );
//    /* @brief Method allowing to add a birth condition.
//     *
//     * This method allows to add a birth condition for a Cell instance. If the
//     * added value is already present in BirthCondition, it is not added.
//     *
//     * @param[in] bCond value of the new birth condition.
//     */
//    void addBirthCondition( const quint8& bCond );
//    /* @brief Method allowing to remove a birth condition.
//     *
//     * This method allows to remove a birth condition for a Cell instance. If
//     * the value to remove doesn't exist, the method does nothing.
//     *
//     * @param[in] bCond value of the birth condition to remove.
//     *
//     * @retval true if the birth condition was found and removed successfully,
//     * @retval false if the condition doesn't exist.
//     */
//    bool removeBirthCondition( const quint8& bCond );
//    /* @brief Method allowing to reset the birth conditions.
//     *
//     * This method allows to clear the BirthConditions container.
//     */
//    void clearBirthConditions();
//    /* @brief Getter for the SurvivalConditions.
//     *
//     * This method allows to access SurvivalConditions.
//     *
//     * @return a const reference on SurvivalConditions.
//     */
//    const QList< quint8 >& survivalConditions() const;
//    /* @brief Setter for SurvivalConditions.
//     *
//     * This method allows to modify SurvivalConditions.
//     *
//     * @param[in] conds new values for SurvivalConditions.
//     */
//    void setSurvivalConditions( const QList< quint8 >& conds );
//    /* @brief Method allowing to add a survival condition.
//     *
//     * This method allows to add a survival condition for a Cell instance. If
//     * the added value is already present in SurvivalConditions, it is not
//     * added.
//     *
//     * @param[in] sCond value of the new survival condition.
//     */
//    void addSurvivalCondition( const quint8& sCond );
//    /* @brief Method allowing to remove a survival condition.
//     *
//     * This method allows to remove a survival condition for a Cell instance.
//     * If the value to remove doesn't exist, the method does nothing.
//     *
//     * @param[in] sCond value of the survival condition to remove.
//     *
//     * @retval true if the survival condition was found and removed
//     * successfully, @retval false if the condition doesn't exist.
//     */
//    bool removeSurvivalCondition( const quint8& sCond );
//    /* @brief Method allowing to reset the survival conditions.
//     *
//     * This method allows to clear the SurvivalConditions container.
//     */
//    void clearSurvivalConditions();
    /** @brief Getter for CurrentStatus.
     *
     * This method allows to access CurrentStatus.
     *
     * @return a const reference on CurrentStatus.
     */
    const Status& currentStatus() const;
    #ifdef QT_DEBUG
    /** @brief Setter for CurrentStatus.
     *
     * This method, used in tests only, allows to modify CurrentStatus.
     *
     * @param[in] status new value of CurrentStatus.
     */
    void setCurrentStatus( const Status& status );
    #endif
    /** @brief Getter for FutureStatus.
     *
     * This method allows to access FutureStatus.
     *
     * @return a const reference on FutureStatus.
     */
    const Status& futureStatus() const;
    /** @brief Method computing the value of FutureStatus.
     *
     * This method computes the value of FutureStatus, depending on the state
     * of the neighbouring Cell instance.
     *
     * @retval true if the computation was done correctly, @retval false if the
     * FutureStatus of the current instance is not Unknown.
     */
    bool computeFutureStatus();
    /** @brief Method setting CurrentStatus to FutureStatus and resetting
     * FutureStatus.
     *
     * This method sets the current status of the instance to its future
     * status.
     *
     * If the value of FutureStatus is Unknown, the evolution cannot be
     * performed.
     *
     * @retval true if the evolution was performed correctly, @retval false if
     * not.
     */
    bool evolve();
public slots:
    /** @brief The state toggling slot.
     *
     * This slot allows to change the Cell current status: from Alive to Dead
     * and vice-versa.
     */
    void toggleCurrentStatus();
protected:
    /** @brief List of the neighbouring instances.
     *
     * The neighbouring relationship is materialised by the instance holding a
     * list of pointers.
     */
    QList< Cell* > Neighbours;
    /** @brief List of birth conditions.
     *
     * This container is used to set the birth conditions for each created Cell
     * instance.
     */
    QList< quint8 > BirthConditions;
    /** @brief List of survival conditions.
     *
     * This container is used to set the survival conditions for each created
     * Cell instance.
     */
    QList< quint8 > SurvivalConditions;
    /** @brief Current state of the instance.
     */
    Status CurrentStatus;
    /** @brief Future state of the instance.
     */
    Status FutureStatus;
signals:
    /** @brief The flipping signal.
     *
     * This signal is sent whenever the instance state changes, for instance
     * when toggleCurrentStatus() is executed or when the evolution brings a
     * state change.
     *
     * @param[out] cell pointer on the changed (i.e. current) instance.
     */
    void flipped( Cell* cell );
};

#endif // CELL_HPP
